package org.smith.docker.sample.service;

import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 栈内存溢出
 */
@Component
public class StackOOMService {

    public int stackLength = 1;

    /**
     * 递归调用自己
     *
     * 默认配置：stack length: 19204
     *
     * 把栈的内存设置的小一些
     * -Xss144k：stack length: 1452
     *
     *
     * 每调用一次方法，就会创建一个栈帧，栈的大小越小，栈能够容纳的栈帧个数也会越少，能够递归的次数也会变少。
     */
    public void stackLeak1() {
        stackLength++;
        this.stackLeak1();
    }


    /**
     * 和 stackLeak1 方法的区别是增加了一百个局部变量的定义
     *
     * 默认配置：stack length: 7951
     * -Xss144k：stack length: 82
     *
     * 局部变量是存放在栈帧的局部变量表的，第一段代码没有局部变量，第二段代码有大量的局部变量，因此第二段每个栈帧占用的内存比第一段都要大，相同的栈配置下，能够容纳的栈帧就少。
     */
    public void stackLeak2() {
        long unused0, unused1, unused2, unused3, unused4, unused5, unused6, unused7, unused8, unused9,
                unused10, unused11, unused12, unused13, unused14, unused15, unused16, unused17, unused18, unused19,
                unused20, unused21, unused22, unused23, unused24, unused25, unused26, unused27, unused28, unused29,
                unused30, unused31, unused32, unused33, unused34, unused35, unused36, unused37, unused38, unused39,
                unused40, unused41, unused42, unused43, unused44, unused45, unused46, unused47, unused48, unused49,
                unused50, unused51, unused52, unused53, unused54, unused55, unused56, unused57, unused58, unused59,
                unused60, unused61, unused62, unused63, unused64, unused65, unused66, unused67, unused68, unused69,
                unused70, unused71, unused72, unused73, unused74, unused75, unused76, unused77, unused78, unused79,
                unused80, unused81, unused82, unused83, unused84, unused85, unused86, unused87, unused88, unused89,
                unused90, unused91, unused92, unused93, unused94, unused95, unused96, unused97, unused98, unused99 = 1;
        stackLength++;
        this.stackLeak2();
    }

    public AtomicInteger integer = new AtomicInteger();

    private void dontStop() {
        while (true) {
        }
    }

    /**
     *
     * 本示例可能会造成机器假死，请慎重测试！！！
     * 本示例可能会造成机器假死，请慎重测试！！！
     * 本示例可能会造成机器假死，请慎重测试！！！
     *
     * 不断创建新的线程
     *
     * 不做任何配置能创建 5000 个线程（卡的要死，没法测）
     *
     * =======
     * -Xms=10m -Xmx=10m -Xss=144k -XX:MetaspaceSize=10m
     * =======
     * cat /proc/sys/kernel/threads-max
     * - 作用：系统支持的最大线程数，表示物理内存决定的理论系统进程数上限，一般会很大
     * - 修改：sysctl -w kernel.threads-max=7726
     * =======
     * cat /proc/sys/kernel/pid_max
     * - 作用：查看系统限制某用户下最多可以运行多少进程或线程
     * - 修改：sysctl -w kernel.pid_max=65535
     * =======
     * cat /proc/sys/vm/max_map_count
     * - 作用：限制一个进程可以拥有的VMA(虚拟内存区域)的数量，虚拟内存区域是一个连续的虚拟地址空间区域。
     * 在进程的生命周期中，每当程序尝试在内存中映射文件，链接到共享内存段，或者分配堆空间的时候，这些区域将被创建。
     * - 修改：sysctl -w vm.max_map_count=262144
     * =======
     * ulimit -u
     * - 作用：查看用户最多可启动的进程数目
     * - 修改：ulimit -u 65535
     *
     */
    public void newThread() {
        while (true) {
            Thread thread = new Thread(this::dontStop);
            thread.start();

            System.out.println("线程创建成功，threadName = " + thread.getName());
            integer.incrementAndGet();
        }
    }

}
